package cn.kmsoft.spatialboot.service.executor;

import cn.kmsoft.stgeometry.constant.DBType;
import cn.kmsoft.wololo.object.GeoJsonFeature;
import cn.kmsoft.wololo.object.GeoJsonGeometry;
import com.alibaba.fastjson.JSONObject;
import cn.kmsoft.spatialboot.config.dbswitch.DataSourceContextHolder;
import cn.kmsoft.spatialboot.common.object.TaskParam;
import cn.kmsoft.spatialboot.common.object.TaskResult;
import cn.kmsoft.spatialboot.utils.EllipsoidalAreaCalculator;
import cn.kmsoft.stgeometry.util.GeoJsonUtil;
import cn.kmsoft.stgeometry.util.GeomUtil;
import com.esri.core.geometry.*;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wangq
 * @date 2019/11/17.
 */
public class DifferenceExecutor extends BaseParallelExecutor {
    private static final Logger logger = LoggerFactory.getLogger(DifferenceExecutor.class);

    @Override
    protected TaskResult task(int index, TaskParam param, JSONObject inputFeature) {
        String dbInstance = param.getInstance();
        DataSourceContextHolder.setDataSourceType(dbInstance);
        String dbTypeName = param.getDbType();
        DBType dbType = DBType.getDBTypeByName(dbTypeName);

        Map<String, Object> props = new HashMap<>();
        //某一个新增建设用地地块
        JSONObject inputGeometry = inputFeature.getJSONObject("geometry");
        JSONObject inputProperties = inputFeature.getJSONObject("properties");
        String dkbh = inputProperties.get("OBJECTID").toString();
        for (Object key : inputProperties.keySet()) {
            props.put(key.toString(), inputProperties.get(key.toString()));
        }

        //1.擦除操作
        List<GeoJsonFeature> diffResFeatures = null;
        try {
            //用所有的历史征地进行擦除某一个新增建设用地地块运算
            //layerDifferenceDao.differenceByGeoJson(id, wkt, wkid)
            List<Map<String, Object>> diffResults = param.getSpatialOperate().query(
                    param.getTableId(),
                    GeomUtil.geojsonToWkt(inputGeometry.toString()),
                    param.getWkid(),
                    param.getFgeo_wkid());
            diffResFeatures = GeoJsonUtil.parse(diffResults, param.getWkid(), dbType);
        } finally {
            DataSourceContextHolder.clearDataSourceType();
        }

        //2.结果整理
        List<GeoJsonFeature> features = new ArrayList<>();
        if (diffResFeatures == null) {
            System.out.println();
            System.out.println(String.format("dkbh：%s ---> diffResFeatures is null ", dkbh));

            GeoJsonFeature outFeature = new GeoJsonFeature();
            outFeature.setType("Feature");
            outFeature.setProperties(props);
            outFeature.setGeometry(
                    JSONObject.parseObject(
                            inputGeometry.toString(),
                            GeoJsonGeometry.class)
            );

            try {
                Geometry inputGeo = GeometryEngine.geometryFromGeoJson(
                        inputGeometry.toString(),
                        GeoJsonImportFlags.geoJsonImportDefaults,
                        Geometry.Type.Unknown
                ).getGeometry();
                double xzarea = inputGeo.calculateArea2D();
                double syarea = xzarea;
                outFeature.getProperties().put("XZAREA", xzarea);//新增建设用地面积
                outFeature.getProperties().put("AREA", syarea);//剩余面积
            } catch (JSONException e) {
                e.printStackTrace();
            }

            features.add(outFeature);
        } else {
            System.out.println();
            System.out.println(String.format("dkbh：%s ---> diff size: %s ", dkbh, diffResFeatures.size()));
            for (int i = 0; i < diffResFeatures.size(); i++) {
                GeoJsonFeature diffFea = diffResFeatures.get(i);
                System.out.println(String.format("%d,%s", i, diffFea.toString()));
            }

            int diffFeaCount = diffResFeatures.size();
            //第一种情况，diffResFeatures.size()==0
            if (diffFeaCount == 0) {
                GeoJsonFeature outFeature = new GeoJsonFeature();
                outFeature.setType("Feature");
                outFeature.setProperties(props);
                outFeature.setGeometry(
                        JSONObject.parseObject(
                                inputGeometry.toString(),
                                GeoJsonGeometry.class)
                );
                try {
                    Geometry inputGeo = GeometryEngine.geometryFromGeoJson(
                            inputGeometry.toString(),
                            GeoJsonImportFlags.geoJsonImportDefaults,
                            Geometry.Type.Unknown
                    ).getGeometry();

                    double xzarea = inputGeo.calculateArea2D();
                    double syarea = xzarea;
                    outFeature.getProperties().put("XZAREA", xzarea);//新增建设用地面积
                    outFeature.getProperties().put("AREA", syarea);//剩余面积
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                features.add(outFeature);
            }

            //第二种情况，diffResFeatures.size()==1
            if (diffFeaCount == 1) {
                Geometry intersectResult = null;
                GeoJsonFeature outFeature = new GeoJsonFeature();
                outFeature.setType("Feature");
                outFeature.setProperties(props);
                outFeature.setGeometry(diffResFeatures.get(0).getGeometry());

                try {
                    Geometry inputGeo = GeometryEngine.geometryFromGeoJson(
                            inputGeometry.toString(),
                            GeoJsonImportFlags.geoJsonImportDefaults,
                            Geometry.Type.Unknown
                    ).getGeometry();

                    intersectResult = GeometryEngine.geometryFromGeoJson(
                            JSONObject.toJSONString(diffResFeatures.get(0).getGeometry()),
                            GeoJsonImportFlags.geoJsonImportDefaults,
                            Geometry.Type.Unknown
                    ).getGeometry();
                    double xzarea = inputGeo.calculateArea2D();
                    double syarea = intersectResult.calculateArea2D();
                    outFeature.getProperties().put("XZAREA", xzarea);//新增建设用地面积
                    outFeature.getProperties().put("AREA", syarea);//剩余面积
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                features.add(outFeature);
            }

            // 第三种情况，diffResFeatures.size() >= 2
            if (diffFeaCount > 1) {
                Geometry intersectResult = null;
                for (int j = 0; j < diffResFeatures.size() - 1; j++) {
                    if (diffResFeatures.get(j).getGeometry() == null || diffResFeatures.get(j + 1).getGeometry() == null) {
                        intersectResult = null;
                        break;
                    }
                    try {
                        if (intersectResult == null) {
                            intersectResult = GeometryEngine.geometryFromGeoJson(
                                    JSONObject.toJSONString(diffResFeatures.get(j).getGeometry()),
                                    GeoJsonImportFlags.geoJsonImportDefaults,
                                    Geometry.Type.Unknown
                            ).getGeometry();
                        }
                        Geometry intersect = GeometryEngine.geometryFromGeoJson(
                                JSONObject.toJSONString(diffResFeatures.get(j + 1).getGeometry()),
                                GeoJsonImportFlags.geoJsonImportDefaults,
                                Geometry.Type.Unknown
                        ).getGeometry();
                        //为啥要做这个相交操作呢
                        intersectResult = GeometryEngine.intersect(intersectResult, intersect, SpatialReference.create(param.getWkid()));
                        if (intersectResult.isEmpty()) {
                            break;
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                if (intersectResult != null && !intersectResult.isEmpty()) {
                    GeoJsonFeature outFeature = new GeoJsonFeature();
                    outFeature.setType("Feature");
                    outFeature.setProperties(props);
                    outFeature.setGeometry(
                            JSONObject.parseObject(
                                    GeometryEngine.geometryToGeoJson(param.getWkid(), intersectResult),
                                    GeoJsonGeometry.class)
                    );

                    try {
                        Geometry inputGeo = GeometryEngine.geometryFromGeoJson(
                                inputGeometry.toString(),
                                GeoJsonImportFlags.geoJsonImportDefaults,
                                Geometry.Type.Unknown
                        ).getGeometry();

                        double xzarea = inputGeo.calculateArea2D();
                        double syarea = intersectResult.calculateArea2D();
                        outFeature.getProperties().put("XZAREA", xzarea);//新增建设用地面积
                        outFeature.getProperties().put("AREA", syarea);//剩余面积
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    if (param.isReturnEllipsoidalArea()) {
                        EllipsoidalAreaCalculator calculator = new EllipsoidalAreaCalculator(105.0, "EPSG:2332", "EPSG:4610");
                        outFeature.getProperties().put(
                                "TQMJ",
                                calculator.getFeatureArea(
                                        GeometryEngine.geometryToWkt(intersectResult, WktExportFlags.wktExportDefaults),
                                        param.getDigits()
                                )
                        );
                    }

                    features.add(outFeature);
                }
            }
        }

        TaskResult result = new TaskResult();
        result.setFeatures(features);
        result.setIndex(index);

        return result;
    }
}
